package cn.sciento.onelink;

import cn.sciento.onelink.error.LinkErrorCode;
import cn.sciento.onelink.exception.CommonException;
import cn.sciento.onelink.exception.RequestException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.TypeFactory;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.HttpClients;

import java.io.IOException;
import java.lang.reflect.Array;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

public class DefaultLinkClient implements ILinkClient {
    public static final String HOST = "https://api.iot.10086.cn";
    public static final String VERSION =  "v5";
    private String host;
    private String version;
    private HttpClient httpClient;
    private ObjectMapper objectMapper;
    private ITokenManager tokenManager;
    private String appId;

    public DefaultLinkClient(String host,String version,TokenManager tokenManager){
        this.httpClient = HttpClients.createDefault();
        objectMapper = new ObjectMapper();
        this.host = host;
        this.version = version;
        this.tokenManager = tokenManager;
    }

    public DefaultLinkClient(String host,String version){
       this(host,version,null);
    }
    public DefaultLinkClient(){
        this(HOST,VERSION);
    }

    public static JavaType getJavaType(Type type) {
        if (type instanceof ParameterizedType) {
            Type[] actualTypeArguments = ((ParameterizedType) type).getActualTypeArguments();
            Class rowClass = (Class) ((ParameterizedType) type).getRawType();
            JavaType[] javaTypes = new JavaType[actualTypeArguments.length];
            for (int i = 0; i < actualTypeArguments.length; i++) {
                javaTypes[i] = getJavaType(actualTypeArguments[i]);
            }
            return TypeFactory.defaultInstance().constructParametricType(rowClass, javaTypes);
        } else {
            Class cla = (Class) type;
            return TypeFactory.defaultInstance().constructParametricType(cla, new JavaType[0]);
        }
    }

    public <T extends Object> List<T> getCommonResponse(LinkRequest<CommonResponse<T>> request) throws IOException, URISyntaxException {
        System.out.println(request.getUrl());
        request.setToken(tokenManager.getToken());
        request.setHost(this.host);
        request.setVersion(this.version);
        HttpResponse httpResponse = httpClient.execute(request.generate());
        if(httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK){
            Type types = request.getClass().getGenericSuperclass();
            Type[] params = ((ParameterizedType) types).getActualTypeArguments();
            JavaType clas = getJavaType(params[0]);
            CommonResponse<T> resp = objectMapper.readValue(httpResponse.getEntity().getContent(),clas);
            if(Integer.parseInt(resp.getStatus()) == LinkErrorCode.LINK_OK.getCode()){
                return resp.getResult();
            }else {
                throw new CommonException(resp.getMessage());
            }
        }else {
            throw new RequestException(httpResponse.getStatusLine().getReasonPhrase());
        }
    }
    public void setAppId(String appId) {
        this.appId = appId;
    }
    public void setTokenManager(ITokenManager tokenManager) {
        this.tokenManager = tokenManager;
    }

}
